<template>
  <div class="topo-component">
    <TopoHeader :graph="graphRef" />
    <div class="topo-component-content">
      <StencilBox ref="stencilRef" />
      <div id="graph-container"></div>
      <NodeEditBox
        v-model:visible="editBoxVisible"
        :node="selectedNode"
        @setNodedata="setNodedata"
      />
      <ContextMenu
        v-model:cmVisible="cmVisible"
        :contextMenuData="contextMenuData"
        :graph="graphRef"
        @deleteCell="deleteCell"
        @show_editBoxVisible="show_editBoxVisible"
      ></ContextMenu>
    </div>
  </div>
</template>

<script setup>
import { Graph, Shape } from "@antv/x6";
import { Transform } from "@antv/x6-plugin-transform";
import { Selection } from "@antv/x6-plugin-selection";
import { Snapline } from "@antv/x6-plugin-snapline";
import { Keyboard } from "@antv/x6-plugin-keyboard";
import { Clipboard } from "@antv/x6-plugin-clipboard";
import { History } from "@antv/x6-plugin-history";
import { Export } from "@antv/x6-plugin-export";
import TopoHeader from "./components/TopoHeader.vue";
import StencilBox from "@/components/Topo/components/StencilBox.vue";
import HomeSvg from "@/assets/icons/home.svg";
import ContextMenu from "@/components/Topo/components/contextMenu.vue";
import NodeEditBox from "@/components/Topo/components/nodeEditBox.vue";
import { ref, onMounted } from "vue";

const graphRef = ref(null);
const stencilRef = ref(null);

// 右击菜单
const cmVisible = ref(false);
const contextMenuData = ref({
  x: 0,
  y: 0,
  cell: null,
});

// 编辑框控制
const editBoxVisible = ref(false);
const selectedNode = ref(null);

// #region 注册节点
Graph.registerNode(
  "org-node",
  {
    width: "100%",
    height: "100%",
    markup: [
      // 文本
      {
        tagName: "text",
        selector: "label",
      },
      // 图片
      {
        tagName: "image",
        selector: "image",
      },
      // {
      //     tagName: 'path',
      //     attrs: {
      //         fill: 'red',
      //         d: "M12 5.69L17 10.19V18H15V12H9V18H7V10.19L12 5.69ZM12 3L2 12H5V20H11V14H13V20H19V12H22L12 3Z"
      //     }
      // }
    ],
  },
  true
);
Graph.registerNode("text-node", {
  width: "100%",
  height: "100%",
  markup: [
    {
      tagName: "text",
      selector: "label",
    },
  ],
});
// #endregion

const initGraph = () => {
  // #region 初始化画布
  graphRef.value = new Graph({
    container: document.getElementById("graph-container"),
    grid: true,
    mousewheel: {
      enabled: true,
      zoomAtMousePosition: true,
      modifiers: "ctrl",
      minScale: 0.5,
      maxScale: 3,
    },
    resizing: true, // 开启节点缩放功能
    connecting: {
      router: "manhattan",
      connector: {
        name: "rounded",
        args: {
          radius: 8,
        },
      },
      anchor: "center",
      connectionPoint: "anchor",
      allowBlank: false,
      snap: {
        radius: 20,
      },
      createEdge() {
        return new Shape.Edge({
          attrs: {
            line: {
              stroke: "#A2B1C3",
              strokeWidth: 2,
              targetMarker: {
                name: "block",
                width: 12,
                height: 8,
              },
            },
          },
          zIndex: 0,
        });
      },
      validateConnection({ targetMagnet }) {
        return targetMagnet;
      },
    },
    highlighting: {
      magnetAdsorbed: {
        name: "stroke",
        args: {
          attrs: {
            fill: "#5F95FF",
            stroke: "#5F95FF",
          },
        },
      },
    },
  });
  // #endregion
};

const show_editBoxVisible = (cell) => {
  // 设置选中的节点数据
  selectedNode.value = cell;
  // 显示编辑框
  editBoxVisible.value = true;
  cmVisible.value = false;
};

const deleteCell = (source) => {
  console.log(source);
  if (source == "contextMenu") {
    graphRef.value.removeCell(contextMenuData.value.cell);
    cmVisible.value = false;
  }
};

const setNodedata = (cell, attrs) => {
  cell.setAttrs(attrs);
};

onMounted(() => {
  initGraph();
  // #region 使用插件
  graphRef.value
    .use(
      new Transform({
        resizing: true,
        rotating: true,
      })
    )
    .use(
      new Selection({
        rubberband: true,
        showNodeSelectionBox: true,
      })
    )
    .use(new Snapline())
    .use(new Keyboard())
    .use(new Clipboard())
    .use(new History())
    .use(new Export());
  // #endregion

  // #region 控制连接桩显示/隐藏
  const showPorts = (ports, show) => {
    for (let i = 0, len = ports.length; i < len; i += 1) {
      ports[i].style.visibility = show ? "visible" : "hidden";
    }
  };
  graphRef.value.on("node:mouseenter", () => {
    const container = document.getElementById("graph-container");
    const ports = container.querySelectorAll(".x6-port-body");
    showPorts(ports, true);
  });

  graphRef.value.on("node:mouseleave", () => {
    const container = document.getElementById("graph-container");
    const ports = container.querySelectorAll(".x6-port-body");
    showPorts(ports, false);
  });
  graphRef.value.on("cell:click", ({ e, x, y, cell, view }) => {
    cmVisible.value = false;
  });
  graphRef.value.on("node:click", ({ e, x, y, node, view }) => {
    cmVisible.value = false;
  });
  graphRef.value.on("edge:click", ({ e, x, y, edge, view }) => {
    cmVisible.value = false;
  });
  graphRef.value.on("blank:click", ({ e, x, y }) => {
    cmVisible.value = false;
  });
  graphRef.value.on("node:contextmenu", (e, cell) => {
    console.log(e);
    cmVisible.value = true;
    contextMenuData.value = {
      x: e.x,
      y: e.y,
      show: true,
      cell: e.cell,
    };
  });
  // #endregion

  // #region 初始化图形
  const ports = {
    groups: {
      top: {
        position: "top",
        attrs: {
          circle: {
            r: 4,
            magnet: true,
            stroke: "#5F95FF",
            strokeWidth: 1,
            fill: "#fff",
            style: {
              visibility: "hidden",
            },
          },
        },
      },
      right: {
        position: "right",
        attrs: {
          circle: {
            r: 4,
            magnet: true,
            stroke: "#5F95FF",
            strokeWidth: 1,
            fill: "#fff",
            style: {
              visibility: "hidden",
            },
          },
        },
      },
      bottom: {
        position: "bottom",
        attrs: {
          circle: {
            r: 4,
            magnet: true,
            stroke: "#5F95FF",
            strokeWidth: 1,
            fill: "#fff",
            style: {
              visibility: "hidden",
            },
          },
        },
      },
      left: {
        position: "left",
        attrs: {
          circle: {
            r: 4,
            magnet: true,
            stroke: "#5F95FF",
            strokeWidth: 1,
            fill: "#fff",
            style: {
              visibility: "hidden",
            },
          },
        },
      },
    },
    items: [
      {
        group: "top",
      },
      {
        group: "right",
      },
      {
        group: "bottom",
      },
      {
        group: "left",
      },
    ],
  };
  // #endregion

  // 创建节点 org-node
  const node = graphRef.value.addNode({
    shape: "org-node",
    x: 400,
    y: 100,
    width: 100,
    height: 100,
    attrs: {
      image: {
        // 'xlink:href': 'https://172.17.2.123/api/simulation/static/resourceLibrary/default_image/client/PC.svg',
        "xlink:href": HomeSvg,
        // 居中
        xAlign: "middle",
        yAlign: "top",
        refX: "50%",
        // refY: '40%',
        // 根据外框g进行缩放
        refWidth2: "90%",
        refHeight2: "90%",
      },
      label: {
        text: "rect",
        fontSize: 16,
        // 居中
        xAlign: "middle",
        yAlign: "middle",
        refX: "50%",
        refY: "90%",
      },
    },
    ports: ports,
  });
  stencilRef.value.renderStencilNode(graphRef.value);
});

/**
 * @description 处理节点更新
 * @param {Object} updatedNode - 更新后的节点数据
 */
const handleNodeUpdate = (updatedNode) => {
  if (!updatedNode || !updatedNode.id) return;

  // 查找节点
  const node = graphRef.value.getCellById(updatedNode.id);
  if (!node) return;

  // 更新节点数据
  node.setData({
    ...node.getData(),
    ...updatedNode,
  });

  // 更新节点显示文本
  if (updatedNode.name) {
    node.attr("label/text", updatedNode.name);
  }

  // 可以根据需要更新其他视觉属性
};
</script>

<style lang="scss" scoped>
.topo-component,
#graph-container {
  width: 100%;
  height: 100%;
  background-color: #fff;
}

.topo-component-content {
  position: relative;
  height: calc(100% - 40px);
  width: 100%;
}
</style>
